package com.cswnode.Service.impl;

import com.cswnode.Entity.User;
import com.cswnode.Service.FollowerService;
import com.cswnode.Service.UserService;
import com.cswnode.Util.Constant;
import com.cswnode.Util.RedisKeyUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author csw
 * @create 2020/10/4 1:21
 */
@Service
public class FollowerServiceImpl implements FollowerService {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private UserService userService;

    @Override
    public void follow(int userId, int entityType, int entityId) {
        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                String follower = RedisKeyUtil.getFollowersKey(entityId,entityType);
                String fans = RedisKeyUtil.getFonsKey(userId,entityType);
                operations.multi();
                redisTemplate.opsForZSet().add(follower,userId,System.currentTimeMillis());
                redisTemplate.opsForZSet().add(fans,entityId,System.currentTimeMillis());

                return operations.exec();
            }
        });
    }

    @Override
    public void unFollow(int userId, int entityType, int entityId) {
        redisTemplate.execute(new SessionCallback() {
            @Override
            public Object execute(RedisOperations operations) throws DataAccessException {
                String follower = RedisKeyUtil.getFollowersKey(entityId,entityType);
                String fans = RedisKeyUtil.getFonsKey(userId,entityType);
                operations.multi();
                redisTemplate.opsForZSet().remove(follower,userId);
                redisTemplate.opsForZSet().remove(fans,entityId);
                return operations.exec();
            }
        });
    }

    @Override
    public long findFansCount(int entityId, int entityType) {
        String followerCount = RedisKeyUtil.getFollowersKey(entityId,entityType);
        return redisTemplate.opsForZSet().zCard(followerCount);
    }

    @Override
    public long findFollowerCount(int userId, int entityType) {
        String fansCount = RedisKeyUtil.getFonsKey(userId,entityType);
        return redisTemplate.opsForZSet().zCard(fansCount);
    }

    @Override
    public boolean findFollowerStatus(int userId, int entityId, int entityType) {
        String fansKey = RedisKeyUtil.getFonsKey(userId,entityType);
        return redisTemplate.opsForZSet().score(fansKey,entityId) != null;
    }

    @Override
    public List<Map<String, Object>> findFollowerList(int userId, int offset, int limit) {
        String FollowerKey = RedisKeyUtil.getFonsKey(userId, Constant.ENTITY_TYPE_USER);
        Set<Integer> targetIds = redisTemplate.opsForZSet().reverseRange(FollowerKey, offset, offset + limit - 1);
        if (targetIds == null){
            return null;
        }
        List<Map<String,Object>> list = new ArrayList<>();
        for (Integer targetId : targetIds){
            Map<String,Object> map = new HashMap<>();
            User user = userService.findUserById(targetId);
            map.put("user",user);
            Double score = redisTemplate.opsForZSet().score(FollowerKey, targetId);
            map.put("followTime",new Date(score.longValue()));
            list.add(map);
        }
        return list;
    }

    @Override
    public List<Map<String, Object>> findFansList(int userId, int offset, int limit) {
        String FansKey = RedisKeyUtil.getFollowersKey(userId, Constant.ENTITY_TYPE_USER);
        Set<Integer> targetIds = redisTemplate.opsForZSet().reverseRange(FansKey, offset, offset + limit - 1);
        if (targetIds == null){
            return null;
        }
        List<Map<String,Object>> list = new ArrayList<>();
        for (Integer targetId : targetIds){
            Map<String,Object> map = new HashMap<>();
            User user = userService.findUserById(targetId);
            map.put("user",user);
            Double score = redisTemplate.opsForZSet().score(FansKey, targetId);
            map.put("followTime",new Date(score.longValue()));
            list.add(map);
        }
        return list;
    }
}
